package com.changgou.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.goods.pojo.Sku;
import com.changgou.search.dao.SkuEsMapper;
import com.changgou.search.pojo.SkuInfo;
import com.changgou.search.service.SkuService;
import entity.Result;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ResultsMapper;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 描述
 *
 * @author ljh
 * @version 1.0
 * @package com.changgou.search.service.impl *
 * @Date 2019-11-28
 * @since 1.0
 */
@Service
public class SkuServiceImpl implements SkuService {
    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private SkuEsMapper skuEsMapper;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private SearchResultMapperImpl searchResultMapperImpl;

    @Override
    public void importES() {
        //1.调用商品微服务的feign获取符合条件的数据
        Result<List<Sku>> listResult = skuFeign.findStatus("1");

        List<Sku> list = listResult.getData();  //转换为字符串
        String jsonString = JSON.toJSONString(list); //在json格式的转换string

        //转换为skuinfo的类
        List<SkuInfo> skuInfos = JSON.parseArray(jsonString, SkuInfo.class);


        for (SkuInfo skuInfo : skuInfos) {
            //获得规格
            String spec = skuInfo.getSpec();// "{"电视音响效果":"小影院","电视屏幕尺寸":"20英寸","尺码":"165"}"
            //把规格转换为map格式
            Map<String, Object> specMap = JSON.parseObject(spec, Map.class);
            //最后设置对应的specmap
            skuInfo.setSpecMap(specMap);
        }

        //2.导入到ES中
        skuEsMapper.saveAll(skuInfos);
    }

    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {
        //1.获取关键字数据
        String keywords = searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)) {
            keywords = "华为";//设置默认
        }
        //2.创建一个查询对象构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();


        //3.设置查询的条件  匹配查询  : 先分词 再搜索


        //3.1 分组查询  按照商品分类 进行分组查询
        //select category_name from tb_sku where name like '%华为%' GROUP BY category_name;
        //指定一个分组的别名skuCategorygroup
        // field("categoryName") 指定要分组的字段
        // size(500) 设置展示的最多的数据量
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategorygroup").field("categoryName").size(50000));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandgroup").field("brandName").size(50000));

        //3.2 根据规格进行分组查询  ?

        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecgroup").field("spec.keyword").size(5000000));

        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name", keywords));


        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //3.3 商品分类的过滤查询
        String category = searchMap.get("category");
        if (!StringUtils.isEmpty(category)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", category));
        }

        //3.4 商品品牌的过滤查询
        String brand = searchMap.get("brand");
        if (!StringUtils.isEmpty(brand)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", brand));
        }

        //3.5 商品规格的过滤查询  : 语法:  specMap.规格名.keyword:规格选项值
        for (String key : searchMap.keySet()) {
            // key :  就是 spec_网络制式  keyowrds  brand ....
            if (key.startsWith("spec_")) {
                String value = searchMap.get(key);//电信2G
                boolQueryBuilder.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
            }
        }
        //3.6 商品的价格区间的晒选
        String price = searchMap.get("price");//  0-1000  3000-*
        if (!StringUtils.isEmpty(price)) {
            String[] split = price.split("-");
            if (split[1].equalsIgnoreCase("*")) {
                //3000以上
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(split[0]));//范围查询
            } else {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(split[0], true).to(split[1], true));//范围查询
            }
        }


        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);//设置所有的过滤条件


        //分页查询

        //参数1  指定的就是当前的页码  如果是0 表示第一个页
        String pageNum = searchMap.get("pageNum");
        Integer pageNo=1;
        if (!StringUtils.isEmpty(pageNum)) {
            pageNo = Integer.parseInt(pageNum);
        }
        Integer pageSize = 40;
        //参数2  指定的每页显示的行
        Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
        nativeSearchQueryBuilder.withPageable(pageable);


        //排序查询
        String sortField = searchMap.get("sortField");//price
        String sortRule = searchMap.get("sortRule");//ASC / DESC
        if(!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)) {
            nativeSearchQueryBuilder.withSort(
//                    SortBuilders.fieldSort(sortField).order(SortOrder.valueOf(sortRule))
                    SortBuilders.fieldSort(sortField).order(sortRule.equalsIgnoreCase("ASC")?SortOrder.ASC:SortOrder.DESC)
            );
        }

        //设置高亮 设置高亮显示字段 设置前缀和后缀
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name"))
                .withHighlightBuilder(new HighlightBuilder().preTags("<em style=\"color:red\">").postTags("</em>"));



        //4.构建查询对象(有查询语法)
        NativeSearchQuery query = nativeSearchQueryBuilder.build();
        //5.执行查询  获取高亮 自定义 高亮数据的映射.

        AggregatedPage<SkuInfo> skuInfos = elasticsearchTemplate.queryForPage(query, SkuInfo.class, searchResultMapperImpl);
        //6.获取结果
        int totalPages = skuInfos.getTotalPages();//总页数
        long totalElements = skuInfos.getTotalElements();//总记录数
        List<SkuInfo> content = skuInfos.getContent();//当前页的记录
        for (SkuInfo skuInfo : content) {
            System.out.println("是否高亮:"+skuInfo.getName());
        }


        //6.1 获取分组的结果  商品分类的分组
        List<String> categoryList = getStringsByGroupName(skuInfos, "skuCategorygroup");
        //6.2 获取分组的结果  商品品牌的分组
        List<String> brandList = getStringsByGroupName(skuInfos, "skuBrandgroup");

        //6.3 获取分组的结果  商品规格分组 操作之后返回一个要的map
        StringTerms stringTermsSpec = (StringTerms) skuInfos.getAggregation("skuSpecgroup");


        Map<String, Set<String>> specMap = getStringSetMap(stringTermsSpec);


        //7.封装结果返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("total", totalElements);
        resultMap.put("totalPages", totalPages);
        resultMap.put("rows", content);
        resultMap.put("categoryList", categoryList);
        resultMap.put("brandList", brandList);
        resultMap.put("pageNum",pageNo);
        resultMap.put("pageSize",pageSize);
        //规格的列表数据
        resultMap.put("specMap", specMap);
        return resultMap;
    }

    private List<String> getStringsByGroupName(AggregatedPage<SkuInfo> skuInfos, String groupName) {
        List<String> list = new ArrayList<>();
        StringTerms categoryStringTerms = (StringTerms) skuInfos.getAggregation(groupName);
        if (categoryStringTerms != null) {
            for (StringTerms.Bucket bucket : categoryStringTerms.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();//分类名称
                list.add(keyAsString);
            }
        }
        return list;
    }

    /**
     * 获取数据 转换成map
     *
     * @param stringTermsSpec
     * @return
     */
    private Map<String, Set<String>> getStringSetMap(StringTerms stringTermsSpec) {
        if (stringTermsSpec != null) {
            Map<String, Set<String>> specMap = new HashMap<String, Set<String>>();
            Set<String> values = new HashSet<String>();
            for (StringTerms.Bucket bucket : stringTermsSpec.getBuckets()) {
                // {"手机屏幕尺寸":"5.5寸","网络":"联通4G","颜色":"红","测试":"实施","机身内存":"16G","存储":"32G","像素":"300万像素"}
                String keyAsString = bucket.getKeyAsString();//规格的数据
                //转换成map 处理
                Map<String, String> map = JSON.parseObject(keyAsString, Map.class);
                //循环遍历
                for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
                    String key = stringStringEntry.getKey();//  手机屏幕尺寸
                    String value = stringStringEntry.getValue();//5寸

                    values = specMap.get(key);
                    if (values == null) {
                        values = new HashSet<>();
                    }
                    values.add(value);

                    specMap.put(key, values);
                }
            }
            return specMap;
        }
        return new HashMap<>();
    }
}
